﻿using Microsoft.AspNetCore.Mvc.Controllers;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using RAP.Framework.Libary.Utils;
using Microsoft.AspNetCore.Mvc.Filters;
using RAP.Web.Libary.Common;
using RAP.Framework.Libary.DataSource;
using RAP.Web.Libary.Config;
using RAP.Web.Libary.Common.Model;
using RAP.Web.Libary.Service.Session;
using RAP.Framework.Libary.Lock;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using RAP.Framework.Libary.DataSource.Model;
using RAP.Framework.Libary.DataSource.Context;

namespace RAP.Web.Libary.Controller.Attributes
{
#pragma warning disable 4014

  /// <summary>
  /// 标记当前Action不需要获取键值对参数，由开发者自行获取
  /// </summary>
  public class QueryParamsAttribute : Attribute
  {
    /// <summary>
    /// 获取或设置是否忽略底层框架默认对参数的处理，如果为true，则有开发者自己处理参数
    /// </summary>
    public bool IgnoreParams { get; set; } = false;

    private string[] _requireParams = null;
    /// <summary>
    /// 必要参数
    /// </summary>
    public string RequireParams { get; set; }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    protected string[] GetRequireParams()
    {
      if (_requireParams == null)
      {
        _requireParams = RequireParams.Split(',');
      }
      return _requireParams;
    }

    private static object _logLockObject = new object();

    /// <summary>
    /// 
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public static async Task<bool> ProcessAttributes(ActionExecutingContext context)
    {
      var actionMethod = (context.ActionDescriptor as ControllerActionDescriptor).MethodInfo;
      var controller = context.Controller as IWebController;
      var attr = actionMethod.GetCustomAttribute<QueryParamsAttribute>();
      if (attr == null || !attr.IgnoreParams)
      {
        //如果Action的参数为0个且Action不包含IgnoreParamsAttribute属性，则将Request.Body、Request.Queries中提交的数据转换成键值对
        var parameters = actionMethod.GetParameters();
        var parameterTypes = new Dictionary<string, Type>();
        foreach (var parameter in parameters)
        {
          if (parameter.GetCustomAttribute<FromServicesAttribute>() != null)
          {
            continue;
          }
          parameterTypes.Add(parameter.Name, parameter.ParameterType);
        }

        controller.QueryParams = await context.GetParams<IQueryParams>(parameterTypes, FieldConsts.TokenField) as IAPIQueryParams;
        var queryParams = controller.QueryParams;

        //处理必要参数
        if (attr != null && attr.RequireParams.IsNotNullOrEmpty())
        {
          var requireParams = attr.GetRequireParams();
          if (requireParams != null)
          {
            foreach (var paramName in requireParams)
            {
              if (paramName.IsNullOrEmpty())
              {
                continue;
              }
              var paramVal = queryParams.ToString(paramName.Trim());
              if (paramVal.IsNullOrEmpty())
              {
                return false;
              }
            }
          }
        }

        var refuseParams = new string[] {
          FieldConsts.IsAdminField,
          FieldConsts.IsSuperAdmin,
          FieldConsts.IPAddressField,
          FieldConsts.UserIdField,
          FieldConsts.ShowLogosField,
          FieldConsts.UserSessionField,
          ServiceUtils.ALLOW_EMPTY_SQL_FIELD,
          ServiceUtils.TSQL_NEED_TRANSACTION,
          ServiceUtils.SQL_FIELD,
          ServiceUtils.TEMPLATE_FIELD,
          ServiceUtils.DATA_SOURCE_FIELD,
          ServiceUtils.CACHE_PROXY_KEY_FIELD,
        };
        //移除不允许从客户端许传入的参数
        refuseParams.Map(key =>
        {
          queryParams.Remove(key);
          return true;
        });
        if (queryParams.UserSession == null || !queryParams.UserSession.UserInfo.IsAdmin)
        {
          //如果没有会话或者会话不是管理员，则移除debug参数
          queryParams.Debug = false;
        }
        queryParams[FieldConsts.IPAddressField] = context.HttpContext.GetIPAddress();
        if (queryParams.ShowLogs)
        {
          var path = context.HttpContext.Request.Path;
          var paramsJSON = controller.QueryParams.ToJSON();
          Task.Run(() =>
          {
            lock (_logLockObject)
            {
              Console.ForegroundColor = ConsoleColor.White;
              Console.Write($"[{DateTime.Now.ToDateTimeString()}] > ");
              Console.ForegroundColor = ConsoleColor.Green;
              Console.Write($"{path}");
              Console.ForegroundColor = ConsoleColor.White;
              Console.WriteLine($" : {paramsJSON}\r\n");
            }
          });
        }
      }
      else if (attr.IgnoreParams)
      {
        //自由处理参数
        controller.QueryParams = context.HttpContext.Request.GetService<IQueryParams>() as IAPIQueryParams;
      }
      return true;
    }
  }
}
